/***
    Amrita ITEWS - Copyright (C) 2009 Amrita Vishwa Vidyapeetham, Amritapuri.
                                       (http://www.amrita.edu)
    ***************************************************************************
    This file is part of the Amrita ITEWS distribution.
    Amrita ITEWS is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License (version 2) as published
    by the Free Software Foundation AND MODIFIED BY the Amrita ITEWS exception.
    ***NOTE*** The exception to the GPL is included to allow you to distribute
    a combined work that includes Amrita ITEWS without being obliged to provide
    the source code for proprietary components outside of the Amrita ITEWS
    software. Amrita ITEWS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    Public License for more details. You should have received a copy of the GNU
    General Public License and the Amrita ITEWS license exception along with
    Amrita ITEWS if not then it can be viewed here:
    http://itews.amrita.ac.in/license.html.


    Documentation, latest information, license and contact details are at:
    http://itews.amrita.ac.in/


    Amrita ITEWS source code can be found at:
    http://code.google.com/p/itews


    The initial code-base of Amrita ITEWS was developed by Amrita Vishwa
    Vidyapeetham as part of the project titled,"Intelligent & Interactive
    Telematics using Emerging Wireless Technologies for Transport Systems
    (ITEWS)" sponsored by Technology Information Forecasting and Assessment
    Council (TIFAC), India.
***/

/*! \file eventq.c
    \brief Event Queue Implementation.
*/

#include <eventq.h>
#include <log_api.h>
#include <string.h>
#include <stdlib.h>

eventq_entry_t entries[EVENTQ_MAX_ENTRIES];

/*! \brief Log Handle. */
extern HLOG _hlog;

/*! \brief Event Queue Subsystem Initialisation Operation.
    \return 0;
 */
STATUS eventq_subsys_init()
{
    uint16 i;

    for( i = 0; i < EVENTQ_MAX_ENTRIES; i++ )
    {
        memset( &entries[i], 0, sizeof( eventq_entry_t ) );
    }
    return 0;
}


/*! \brief Event Queue Registration Operation.
    \param eventq_name The name of the event queue.
    \param eventq_ops A pointer to the eventq_ops_t structure.
    \param max_openers Maximum Number of Openers possible for the Event Queue.
    \return 0 on success.
    \return -EOVERFLOW Eventq Entries exceeded MAX_ENTRIES.
 */
STATUS eventq_register( const char *eventq_name, eventq_ops_t *eventq_ops, int32 max_openers )
{
    uint16 i;
    uint16 j;

    j = 0;
    for( i = 0; i < EVENTQ_MAX_ENTRIES;  i++ )
    {
        if( entries[i].eventq_name == NULL )
        {
            entries[i].eventq_name = eventq_name;
            entries[i].ops = eventq_ops;
            j++;

            if( j == max_openers )  /*Completed Registering EventQ for max_openers.*/
                return 0;
        }
    }

    log_warning( &_hlog, "eventq.c : eventq_register", "Eventq Registerig failed.Entries exceeded MAX_ENTRIES.\n", -EOVERFLOW ) ;
    return -EOVERFLOW;
}

/*! \brief Event Queue Opening Operation.
    \param eventq_name The name of the event queue.
    \param opener_name The name of the application which opens the particular event queue.
    \param h The event handler.
    \return 0 on success.
    \return -EINVAL if Specified EventQ Not Present.
    \note Refer: serial_eventq_open, stream_eventq_open, dgram_eventq_open, thread_eventq_open.
 */
STATUS eventq_open( const char * eventq_name, const char *opener_name, HEVENTQ *h )
{
    uint16 i;
    STATUS status;

    for( i = 0 ; i < EVENTQ_MAX_ENTRIES ; i++ )
    {
        if( (entries[i].eventq_name != NULL) && strcmp( entries[i].eventq_name, eventq_name ) == 0 )
        {
            if( entries[i].is_open == EVENTQ_ENTRY_CLOSED )
            {
                *h = i;
                entries[i].is_open = EVENTQ_ENTRY_OPEN;
                entries[i].opener_name = opener_name;
                if( (status = entries[i].ops->open( &entries[i].ctx, eventq_name )) < 0 )
                {
                    *h = EVENTQ_MAX_ENTRIES;
                    entries[i].is_open = EVENTQ_ENTRY_CLOSED;
                    entries[i].opener_name = NULL;
                    log_error( &_hlog, "eventq.c: eventq_open", "Eventq Open Operation Failed.\n", status) ;
                    return status;
                }

                return status;
            }
        }
    }

    log_warning( &_hlog, "eventq.c : eventq_open", "Specified eventq not present.\n", -EINVAL ) ;
    return (-EINVAL);
}

/*! \brief Event Queue Synchronous put Operation.
    \param h EventQ handle.
    \param e event_t.
    \return non-negative value on success.
    \return -EINVAL if Invalid EventQ Handle given as argument.
    \note Refer: serial_eventq_sync_put, stream_eventq_sync_put, dgram_eventq_sync_put, thread_eventq_sync_put.
 */
STATUS eventq_sync_put( HEVENTQ h, event_t *e )
{
    STATUS put_status;
    HRESULT res;

    if( h >= EVENTQ_MAX_ENTRIES || entries[h].eventq_name == NULL )
    {
        log_error( &_hlog, "eventq.c : eventq_sync_put", "Invalid EventQ Handle.\n", -EINVAL ) ;
        return -EINVAL;
    }

    put_status = entries[h].ops->sync_put( &entries[h].ctx, e, res );
    if( put_status < 0 )
    {
        log_warning( &_hlog, "eventq.c : eventq_sync_put", "Synchronous put operation failed.\n", put_status ) ;
        return put_status;
    }

    return (put_status);
}

/*! \brief Event Queue Asynchronous put Operation.
    \param h EventQ handle.
    \param e event_t.
    \return non-negative value on success.
    \note Refer: serial_eventq_async_put, stream_eventq_async_put, dgram_eventq_async_put, thread_eventq_async_put.
 */
STATUS eventq_async_put( HEVENTQ h, event_t *e )
{
    return 0;
}

/*! \brief Event Queue Synchronous get Operation.
    \param h EventQ handle.
    \param e event_t.
    \return non-negative value on success.
    \return -EINVAL if Invalid EventQ Handle given as argument.
    \note Refer: serial_eventq_sync_get, stream_eventq_sync_get, dgram_eventq_sync_get, thread_eventq_sync_get.
 */
STATUS eventq_sync_get( HEVENTQ h, event_t *e )
{
    STATUS get_status;

    if( h >= EVENTQ_MAX_ENTRIES || entries[h].eventq_name == NULL )
    {
        log_error( &_hlog, "eventq.c : eventq_sync_get", "Invalid EventQ Handle.\n", -EINVAL ) ;
        return -EINVAL;
    }
    get_status = entries[h].ops->sync_get( &entries[h].ctx, e );
    if( get_status < 0 )
    {
        log_warning( &_hlog, "eventq.c : eventq_sync_get", "Synchronous get operation failed.\n", get_status ) ;
        return get_status;
    }
    return (get_status);
}

/*! \brief Event Queue Asynchronous get Operation.
    \param h EventQ handle.
    \param e event_t.
    \return non-negative value on success.
    \note Refer: serial_eventq_async_get, stream_eventq_async_get, dgram_eventq_async_get, thread_eventq_async_get.
 */
STATUS eventq_async_get( HEVENTQ h, event_t *e )
{
    return 0;
}

/*! \brief Event Queue Close Operation.
    \param h EventQ Handle.
    \return 0 on success.
    \return -EINVAL if Invalid EventQ Handle given as argument.
    \note Refer: serial_eventq_close, stream_eventq_close, dgram_eventq_close, thread_eventq_close.
 */
STATUS eventq_close( HEVENTQ h )
{
    STATUS close_status;

    if( h >= EVENTQ_MAX_ENTRIES || entries[h].eventq_name == NULL )
    {
        log_error( &_hlog, "eventq.c : eventq_close", "Invalid EventQ Handle.\n", -EINVAL ) ;
        return -EINVAL;
    }
    entries[h].is_open = EVENTQ_ENTRY_CLOSED;
    entries[h].opener_name = NULL;
    close_status = entries[h].ops->close( &entries[h].ctx );
    if( close_status < 0 )
    {
        log_warning( &_hlog, "eventq.c : eventq_close", "Close operation failed.\n", close_status ) ;
        return close_status;
    }
    return close_status;
}

/*! \brief Event Queue Subsystem Layer Cleanup Operation.
    \return 0 on Success else error code.
 */
STATUS eventq_subsys_cleanup()
{
    uint16 i;

    for( i = 0; i < EVENTQ_MAX_ENTRIES; i++ )
    {
        memset( &entries[i], 0, sizeof( eventq_entry_t) );
    }
    return 0;
}
